package com.junko.core.tool;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.servlet.ServletInputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * WEB工具类
 */
public abstract class ToolWeb {

    protected final static Logger log = LogManager.getLogger(ToolWeb.class);

    /**
     * 获取客户端IP地址
     *
     * @param request
     * @return
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (!checkIP(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (!checkIP(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (!checkIP(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
    private static boolean checkIP(String ip) {
        if (ip == null || ip.length() == 0 || "unkown".equalsIgnoreCase(ip)
                || ip.split(".").length != 4) {
            return false;
        }
        return true;
    }

    /**
     * * 获取服务器IP地址
     * * @return
     */
    public static String getServerIp() {
//        try {
//            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
//            while (networkInterfaces.hasMoreElements()) {
//                NetworkInterface ni = (NetworkInterface) networkInterfaces.nextElement();
//                Enumeration<InetAddress> nias = ni.getInetAddresses();
//                while (nias.hasMoreElements()) {
//                    InetAddress ia = (InetAddress) nias.nextElement();
//                    if (!ia.isLinkLocalAddress() && !ia.isLoopbackAddress() && ia instanceof Inet4Address) {
//                        return ia.getHostAddress();
//                    }
//                }
//            }
//        } catch (SocketException e) {
//        }
        Map map = ToolAddress.getIp();
        return map==null?null:(String)map.get(ToolAddress.IP);
    }

    /**
     * 获取项目根目录
     *
     * @param request
     * @return
     */
    public static String getServletContextPath(HttpServletRequest request) {
        return request.getServletContext().getRealPath("/");
    }

    /**
     * 获取上下文URL全路径
     *
     * @param request
     * @return
     */
    public static String getContextPath(HttpServletRequest request) {
        StringBuilder sb = new StringBuilder();
        if (request.getServerPort() != 80) {
            sb.append(request.getScheme()).append("://").append(request.getServerName()).append(":").append(request.getServerPort()).append(request.getContextPath());
        } else {
            sb.append(request.getScheme()).append("://").append(request.getServerName()).append(request.getContextPath());
        }
        return sb.toString();
    }

    /**
     * 获取完整请求路径(含内容路径及请求参数)
     *
     * @param request
     * @return
     */
    public static String getRequestURIWithParam(HttpServletRequest request) {
        return request.getRequestURI() + (request.getQueryString() == null ? "" : "?" + request.getQueryString());
    }

    /**
     * 获取请求的完整地址
     *
     * @param request
     * @return
     */
    public static String getRequestURL(HttpServletRequest request) {
        String param = request.getQueryString();
        String href = "http://" + request.getServerName() //服务器地址
                + (request.getServerPort() == 80 ? "" : ":" + request.getServerPort())         //端口号
                + request.getContextPath()      //项目名称
                + request.getServletPath();     //请求页面或其他地址
        href += StringUtils.isBlank(param) ? "" : "?" + param;//参数
        return href;
    }

    /**
     * 请求的路径，不带参数
     * @param request
     * @return
     */
    public static String getActionKey(HttpServletRequest request) {
        return request.getContextPath() + request.getServletPath();
    }

    /**
     * 发送请求的页面地址
     */
    public static String getReferer(HttpServletRequest request) {
        return request.getHeader("Referer");
    }

    /**
     * 判断是否是异步请求
     */
    public static Boolean isAsync(HttpServletRequest request) {
        if ((StringUtils.isNoneBlank(request.getHeader("accept")) && request.getHeader("accept").indexOf("application/json") > -1 ||
                (request.getHeader("X-Requested-With") != null &&
                        request.getHeader("X-Requested-With").indexOf("XMLHttpRequest") > -1))) {
            return true;
        }
        return false;
    }

    /**
     * 获取请求参数
     *
     * @param request
     * @param name
     * @return
     */
    public static String getParam(HttpServletRequest request, String name) {
        String value = request.getParameter(name);
        if (null != value && !value.isEmpty()) {
            try {
                return URLDecoder.decode(value, ToolString.encoding).trim();
            } catch (UnsupportedEncodingException e) {
                log.error("decode异常：" + value);
                return value;
            }
        }
        return value;
    }

    /**
     * 获取ParameterMap
     *
     * @param request
     * @return
     */
    public static Map<String, String> getParamMap(HttpServletRequest request) {
        Map<String, String> map = new HashMap<String, String>();
        Enumeration<String> enume = request.getParameterNames();
        while (enume.hasMoreElements()) {
            String name = (String) enume.nextElement();
            map.put(name, request.getParameter(name));
        }
        return map;
    }

    /**
     * 输出servlet文本内容
     *
     * @param response
     * @param content
     * @param contentType
     * @author junko
     */
    public static void outPage(HttpServletResponse response, String content, String contentType) {
        try {
            outPage(response, content.getBytes(ToolString.encoding), contentType); // char to byte 性能提升
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 输出servlet文本内容
     *
     * @param response
     * @param content
     * @param contentType
     * @author junko
     */
    public static void outPage(HttpServletResponse response, byte[] content, String contentType) {
        if (contentType == null || contentType.isEmpty()) {
            contentType = "text/html; charset=UTF-8";
        }
        response.setContentType(contentType);
        response.setCharacterEncoding(ToolString.encoding);
        // PrintWriter out = response.getWriter();
        // out.print(content);
        try {
            response.getOutputStream().write(content);// char to byte 性能提升
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 输出CSV文件下载
     *
     * @param response
     * @param content  CSV内容
     * @author junko
     */
    public static void outDownCsv(HttpServletResponse response, String content) {
        response.setContentType("application/download; charset=gb18030");
        try {
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(ToolDateTime.format(ToolDateTime.getDate(), ToolDateTime.pattern_ymd_hms_s) + ".csv", ToolString.encoding));
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        }
        // PrintWriter out = response.getWriter();
        // out.write(content);
        try {
            response.getOutputStream().write(content.getBytes(ToolString.encoding));
        } catch (IOException e) {
            e.printStackTrace();
        }// char to byte 性能提升
        // out.flush();
        // out.close();
    }

    /**
     * 请求流转字符串
     *
     * @param request
     * @return
     */
    public static String requestStream(HttpServletRequest request) {
        InputStream inputStream = null;
        InputStreamReader inputStreamReader = null;
        BufferedReader bufferedReader = null;
        try {
            request.setCharacterEncoding(ToolString.encoding);
            inputStream = (ServletInputStream) request.getInputStream();
            inputStreamReader = new InputStreamReader(inputStream, ToolString.encoding);
            bufferedReader = new BufferedReader(inputStreamReader);
            String line = null;
            StringBuilder sb = new StringBuilder();
            while ((line = bufferedReader.readLine()) != null) {
                sb.append(line);
            }
            return sb.toString();
        } catch (IOException e) {
            log.error("request.getInputStream() to String 异常", e);
            return null;
        } finally { // 释放资源
            if (null != bufferedReader) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    log.error("bufferedReader.close()异常", e);
                }
                bufferedReader = null;
            }

            if (null != inputStreamReader) {
                try {
                    inputStreamReader.close();
                } catch (IOException e) {
                    log.error("inputStreamReader.close()异常", e);
                }
                inputStreamReader = null;
            }

            if (null != inputStream) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error("inputStream.close()异常", e);
                }
                inputStream = null;
            }
        }
    }

    /**
     * 添加cookie
     * @param request		HttpServletRequest
     * @param response		HttpServletResponse
     * @param domain		设置cookie所在域
     * @param path			设置cookie所在路径
     * @param isHttpOnly	是否只读
     * @param name			cookie的名称
     * @param value			cookie的值
     * @param maxAge		cookie存放的时间(以秒为单位,假如存放三天,即3*24*60*60; 如果值为0,cookie将随浏览器关闭而清除)
     */
    public static void addCookie(HttpServletRequest request, HttpServletResponse response,
                                 String domain, String path, boolean isHttpOnly,
                                 String name, String value, int maxAge) {
        Cookie cookie = new Cookie(name, value);

        // 设置cookie所在路径
        if(StringUtils.isEmpty(path)){
            path = request.getContextPath();
        }
        if(StringUtils.isEmpty(path)){
            path = "/";
        }
        cookie.setPath(path);

        // 所在域：比如a1.4bu4.com 和 a2.4bu4.com 共享cookie
        if(StringUtils.isNotEmpty(domain)){
            cookie.setDomain(domain);
        }

        // 是否只读
        try {
            cookie.setHttpOnly(isHttpOnly);
        } catch (Exception e) {
            if(log.isErrorEnabled()) log.error("servlet容器版本太低，servlet3.0以前不支持设置cookie只读" + e.getMessage());
        }

        // https模式传递此cookie，否则忽略此cookie
        String scheme = request.getScheme();
        if(scheme.equals("https")){
            cookie.setSecure(true);
        }

        // 设置cookie的过期时间
        if (maxAge > 0){
            cookie.setMaxAge(maxAge);
        }
        response.addCookie(cookie);
    }

    /**
     * 获取cookie的值
     *
     * @param request
     * @param name
     *            cookie的名称
     * @return
     */
    public static String getCookieValueByName(HttpServletRequest request, String name) {
        Map<String, Cookie> cookieMap = ToolWeb.readCookieMap(request);
        // 判断cookie集合中是否有我们像要的cookie对象 如果有返回它的值
        if (cookieMap.containsKey(name)) {
            Cookie cookie = (Cookie) cookieMap.get(name);
            return cookie.getValue();
        } else {
            return null;
        }
    }

    /**
     * 获得cookie
     *
     * @param request
     * @param name
     * @return
     */
    public static Cookie getCookieByName(HttpServletRequest request, String name) {
        Map<String, Cookie> cookieMap = ToolWeb.readCookieMap(request);
        // 判断cookie集合中是否有我们像要的cookie对象 如果有返回它的值
        if (cookieMap.containsKey(name)) {
            Cookie cookie = (Cookie) cookieMap.get(name);
            return cookie;
        } else {
            return null;
        }
    }

    /**
     * 获得所有cookie
     *
     * @param request
     * @return
     */
    public static Map<String, Cookie> readCookieMap(HttpServletRequest request) {
        Map<String, Cookie> cookieMap = new HashMap<String, Cookie>();
        // 从request范围中得到cookie数组 然后遍历放入map集合中
        Cookie[] cookies = request.getCookies();
        if (null != cookies) {
            for (int i = 0; i < cookies.length; i++) {
                cookieMap.put(cookies[i].getName(), cookies[i]);
            }
        }
        return cookieMap;
    }

//    /**
//     * 效验Referer有效性
//     *
//     * @author junko
//     * @return
//     */
//    public static boolean authReferer(HttpServletRequest request) {
//        String referer = request.getHeader("Referer");
//        if (StringUtils.isNotEmpty(referer)) {
//            referer = referer.toLowerCase();
//            String domainStr = Constant.config_domain_key;
//            String[] domainArr = domainStr.split(",");
//            for (String domain : domainArr) {
//                if (referer.startsWith(domain.trim())) {
//                    return true;
//                }
//            }
//        }
//        return false;
//    }

    /**
     * 去除HTML代码
     *
     * @param inputString
     * @return
     */
    public static String HtmltoText(String inputString) {
        String htmlStr = inputString; // 含HTML标签的字符串
        String textStr = "";
        Pattern p_script;
        java.util.regex.Matcher m_script;
        Pattern p_style;
        java.util.regex.Matcher m_style;
        Pattern p_html;
        java.util.regex.Matcher m_html;
        Pattern p_ba;
        java.util.regex.Matcher m_ba;

        try {
            String regEx_script = "<[\\s]*?script[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?script[\\s]*?>"; // 定义script的正则表达式{或<script[^>]*?>[\\s\\S]*?<\\/script>
            // }
            String regEx_style = "<[\\s]*?style[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?style[\\s]*?>"; // 定义style的正则表达式{或<style[^>]*?>[\\s\\S]*?<\\/style>
            // }
            String regEx_html = "<[^>]+>"; // 定义HTML标签的正则表达式
            String patternStr = "\\s+";

            p_script = Pattern.compile(regEx_script, Pattern.CASE_INSENSITIVE);
            m_script = p_script.matcher(htmlStr);
            htmlStr = m_script.replaceAll(""); // 过滤script标签

            p_style = Pattern.compile(regEx_style, Pattern.CASE_INSENSITIVE);
            m_style = p_style.matcher(htmlStr);
            htmlStr = m_style.replaceAll(""); // 过滤style标签

            p_html = Pattern.compile(regEx_html, Pattern.CASE_INSENSITIVE);
            m_html = p_html.matcher(htmlStr);
            htmlStr = m_html.replaceAll(""); // 过滤html标签

            p_ba = Pattern.compile(patternStr, Pattern.CASE_INSENSITIVE);
            m_ba = p_ba.matcher(htmlStr);
            htmlStr = m_ba.replaceAll(""); // 过滤空格

            textStr = htmlStr;

        } catch (Exception e) {
            System.err.println("Html2Text: " + e.getMessage());
        }
        return textStr;// 返回文本字符串
    }

    /**
     * 把页面的信息替换成我们想要的信息存放数据库里面
     *
     * @param sourcestr 页面得到的信息
     * @return
     */
    public static String getHTMLToString(String sourcestr) {
        if (sourcestr == null) {
            return "";
        }
        sourcestr = sourcestr.replaceAll("\\x26", "&amp;");// &
        sourcestr = sourcestr.replaceAll("\\x3c", "&lt;");// <
        sourcestr = sourcestr.replaceAll("\\x3e", "&gt;");// >
        sourcestr = sourcestr.replaceAll("\\x09", "&nbsp;&nbsp;&nbsp;&nbsp;");// tab键
        sourcestr = sourcestr.replaceAll("\\x20", "&nbsp;");// 空格
        sourcestr = sourcestr.replaceAll("\\x22", "&quot;");// "

        sourcestr = sourcestr.replaceAll("\r\n", "<br>");// 回车换行
        sourcestr = sourcestr.replaceAll("\r", "<br>");// 回车
        sourcestr = sourcestr.replaceAll("\n", "<br>");// 换行
        return sourcestr;
    }

    /**
     * 把数据库里面的信息回显到页面上
     *
     * @param sourcestr 数据库取得的信息
     * @return
     */
    public static String getStringToHTML(String sourcestr) {
        if (sourcestr == null) {
            return "";
        }
        sourcestr = sourcestr.replaceAll("&amp;", "\\x26");// &
        sourcestr = sourcestr.replaceAll("&lt;", "\\x3c");// <
        sourcestr = sourcestr.replaceAll("&gt;", "\\x3e");// >
        sourcestr = sourcestr.replaceAll("&nbsp;&nbsp;&nbsp;&nbsp;", "\\x09");// tab键
        sourcestr = sourcestr.replaceAll("&nbsp;", "\\x20");// 空格
        sourcestr = sourcestr.replaceAll("&quot;", "\\x22");// "

        sourcestr = sourcestr.replaceAll("<br>", "\r\n");// 回车换行
        sourcestr = sourcestr.replaceAll("<br>", "\r");// 回车
        sourcestr = sourcestr.replaceAll("<br>", "\n");// 换行
        return sourcestr;
    }

    public static String isRequestImage(String target) {
        //根据后缀进行判断
        String extension;
        try {
            extension = ToolFile.getExtention(target);
        } catch (Exception e) {
            extension = "." + target.substring(target.lastIndexOf("/") + 1, target.length());
        }
        if(StringUtils.equalsIgnoreCase(extension,".jpg")){
            return "image/jpeg";
        }
        if(StringUtils.equalsIgnoreCase(extension,".png")||
                StringUtils.equalsIgnoreCase(extension,".gif")||
                StringUtils.equalsIgnoreCase(extension,".bmp")){
            return "image/"+extension.substring(1,extension.length());
        }
        return null;
    }
}
